package com.ydd.common.utils;


import com.ydd.common.exception.BusinessException;
import com.ydd.common.exception.ErrRespCode;
import io.jsonwebtoken.security.Keys;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCrypt;
import org.springframework.stereotype.Component;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.util.StringUtils;


import java.security.Key;
import java.util.Calendar;
import java.util.Date;
import java.util.UUID;


@Component
@Slf4j
public class JwtUtil {
    @Autowired
    private RedisUtil redisUtil;

    public static final String KEY = "eyJhbGciOiJIUziJIUzeyJhbGciOeyJhbGciOiJIUzI";
    public static String greUUID() {
        return UUID.randomUUID().toString().replace("-", "");
    }

    /***
     * 创建token
     * @param username 用户名
     * @param userId 用户ID
     * @param platform 来源
     * @param timeout 过期时间
     * @return
     */
    public  String createToken(String username, Integer userId, String platform, int timeout) {
        if(StringUtils.isEmpty(platform)){
            throw new BusinessException(ErrRespCode.CREATE_TOKEN_ERROR.getName());
        }
        if(StringUtils.isEmpty(userId)){
            throw new BusinessException(ErrRespCode.CREATE_TOKEN_ERROR.getName());
        }
        if(StringUtils.isEmpty(username)){
            throw new BusinessException(ErrRespCode.CREATE_TOKEN_ERROR.getName());
        }
        JwtBuilder jwtBuilder = Jwts.builder()
                .signWith(SignatureAlgorithm.HS256,KEY)
                .setIssuedAt(new Date())
                .setSubject(username)
                .claim("platform", platform)
                .claim("id", userId)
                ;

        // 过期时间大于0，设置过期时间,单位分钟
        if (timeout > 0) {
            Date date = greExpiration(timeout);
            jwtBuilder.setExpiration(date);
        }
        String token = jwtBuilder.compact();
        //redis添加token
        int tokenExpire=timeout*1000;

        redisUtil.addWithExpire("token:"+userId,token,tokenExpire);

        return token;
    }

    private static Date greExpiration(int SECOND) {
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.MINUTE, SECOND);
        return calendar.getTime();
    }


    public  String getUsername(String token) {
        return getTokenBody(token).getSubject();
    }
    public  String getUserId(String token) {
        return getTokenBody(token).get("id").toString();
    }

    /***
     * 根据token解析出来源
     * @param token
     * @return
     */
    public  String getPlatform(String token) {
        return getTokenBody(token).get("platform").toString();
    }

    /**
     * 是否已过期
     *
     * @param token token
     */
    public  boolean isExpiration(String token) {
        return getTokenBody(token).getExpiration().before(new Date());
    }

    private static Claims getTokenBody(String token) {

        return Jwts.parserBuilder()
                .setSigningKey(KEY)
                .build()
                .parseClaimsJws(token)
                .getBody();
    }

    public void verifyToken(String token) {
//        //检查redis中的token是否正确
//        String userId = getUserId(token);
//        if(StringUtils.isEmpty(userId)){
//            throw new BusinessException("Token非法");
//        }
//        String redisToken = redisUtil.get("token:"+userId);
//        if (StringUtils.isEmpty(redisToken)){
//            throw new BusinessException("登录过期");
//        }
        try {
            getTokenBody(token);
        } catch (MalformedJwtException e) {
            log.error(e.getMessage(), e);
            throw new BusinessException("Token非法");
        } catch (ExpiredJwtException e) {
            log.error(e.getMessage(), e);
            throw new BusinessException("登录过期");
        }
    }

//    public static void main(String[] args) {
//
//        String token = JwtUtils.createToken("user1", "来源1", 1000*60*60);
//        System.out.println(token);
//    }

    /**
     * 使用BCrypt对明文密码进行哈希加密。
     *
     * @param plainTextPassword 明文密码
     * @return 加密后的密码字符串
     */
    public String encryptPassword(String plainTextPassword) {
        // BCrypt.gensalt()用于生成随机的盐值，参数10表示迭代次数，增加计算难度
        String salt = BCrypt.gensalt(10);
        // BCrypt.hashpw()用于结合盐值对密码进行哈希处理
        String hashedPassword = BCrypt.hashpw(plainTextPassword, salt);
        return hashedPassword;
    }
    /**
     * 验证明文密码是否与存储的哈希密码匹配。
     *
     * @param plainTextPassword 用户输入的明文密码
     * @param storedHash        已存储的密码哈希值
     * @return 密码是否匹配
     */
    public boolean checkPassword(String plainTextPassword, String storedHash) {
        // BCrypt.checkpw()比较明文密码经过相同盐值处理后的哈希值与存储的哈希值是否一致
        return BCrypt.checkpw(plainTextPassword, storedHash);
    }

}
